/////////////////////////////////////////////////////////////////////
//
//  MOE Framework (Meta Object Encapsulation Framework)
//
//  Original Author: Wiksy Wang, 2011
//
/////////////////////////////////////////////////////////////////////

#include "NamePath.h"

#include <boost/assert.hpp>

namespace MOE
{

namespace Name
{

const NamePath NamePath::gEmptyPath = NamePath();

NamePath::NamePath()
	: _path()
	, _delimiter('.')
	, _charSize(1)
	, _splitCount(0)
	, _splitIndices(NULL)
{
}

NamePath::NamePath(const RawByteVector& str, const size_t charSize, const unsigned int delimiter)
	: _path(str)
	, _delimiter(delimiter)
	, _charSize(charSize)
	, _splitCount(0)
	, _splitIndices(NULL)
{
	InitPath(delimiter);
}

NamePath::~NamePath()
{
	delete [] _splitIndices;
}

void NamePath::InitPath(const unsigned int delimiter)
{
	const unsigned int mask = (1 << (_charSize * 8)) - 1;
	const size_t increment = _charSize / sizeof(RawByteVector::value_type);
	const RawByteVector::value_type* dataBegin = _path.data();
	const RawByteVector::value_type* dataEnd = dataBegin + _path.size();
	const RawByteVector::value_type* data = dataBegin;

	// First pass to count number of split characters.
	while (data < dataEnd)
	{
		unsigned int compValue = (*reinterpret_cast<const unsigned int*>(data)) & mask;
		if (compValue == delimiter)
		{
			++_splitCount;
		}

		data += increment;
	}

	// Second pass to store indices.
	if (_splitCount != 0)
	{
		_splitIndices = new size_t[_splitCount];
		size_t currentIndex = 0;
		data = dataBegin;

		while (data < dataEnd)
		{
			unsigned int compValue = (*reinterpret_cast<const unsigned int*>(data)) & mask;
			if (compValue == delimiter)
			{
				_splitIndices[currentIndex] = data - dataBegin;
				++currentIndex;
			}

			data += increment;
		}

		BOOST_ASSERT(currentIndex == _splitCount);
	}
}

size_t NamePath::GetPartStartCharIndex(size_t index) const
{
	BOOST_ASSERT(index <= _splitCount);
	return (index == 0) ? 0 : (_splitIndices[index - 1] + _charSize);
}

size_t NamePath::GetPartEndCharIndex(size_t index) const
{
	return (index >= _splitCount) ? _path.size() : _splitIndices[index];
}

RawByteVectorRef NamePath::GetSubPath(size_t index) const
{
	if (index > _splitCount)
	{
		return RawByteVectorRef();
	}
	else
	{
		size_t splitIndex = GetPartStartCharIndex(index);
		return RawByteVectorRef(_path.data() + splitIndex, _path.size() - splitIndex);
	}
}

RawByteVectorRef NamePath::GetSegment(size_t startIndex, size_t endIndex) const
{
	if (startIndex > endIndex || startIndex > _splitCount)
	{
		return RawByteVectorRef();
	}

	size_t startSplitIndex = GetPartStartCharIndex(startIndex);
	size_t endSplitIndex = GetPartEndCharIndex(endIndex);
	return RawByteVectorRef(_path.data() + startSplitIndex, endSplitIndex - startSplitIndex);
}

}

}
